package cn.com.captureNetPacket.util;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import java.util.UUID;

import cn.com.captureNetPacket.model.WebResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

/**
 * 文件操作相关工具类
 * 
 * @author WuPan
 * @date 2020-06-30
 *
 */
@Slf4j
public class FileUtils {
	private static final String REQ_HEADER_GUID_KEY = "guid";
	private static final String REQ_HEADER_AUTHORIZATION_KEY = "Authorization";
	/**
	 * 
	 * @param filePath 文件路径
	 * @param savePath 保存路径
	 * @return
	 * @throws Exception
	 * @throws FileNotFoundException
	 */
	public static WebResult saveUrlAs(String filePath, String savePath) throws FileNotFoundException {
		WebResult ws = new WebResult();
		log.debug("----文件路径:--->{}-----保存路径:--->{}", filePath, savePath);
		BufferedOutputStream bufferedOutputStream = null;
		BufferedInputStream bufferedInputStream = null;
		String retCode = "";
		String retMsg = "";
		String data ="";
		File targetFile = new File(filePath);
		if (!targetFile.exists()) {
			throw new FileNotFoundException("目标文件不存在");
		}
		try {
			// 判断保存路径是否存在
			File file = new File(savePath);
			if (!file.exists()) {
				file.mkdirs();
			}
			String[] fileArray = filePath.split("/");
			// 获取文件名字
			String fileName = fileArray[fileArray.length - 1];
			log.debug("----文件名:---->{}", fileName);
			bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath));
			// 判断文件的保存路径后面是否以/结尾
			if (!savePath.endsWith("/")) {
				savePath += "/";
			}
			FileOutputStream fileOut = new FileOutputStream(savePath + fileName);
			bufferedOutputStream = new BufferedOutputStream(fileOut);
			byte[] buf = new byte[4096];
			// 读取文件
			int length = bufferedInputStream.read(buf);
			// 保存文件
			while (length != -1) {
				bufferedOutputStream.write(buf, 0, length);
				length = bufferedInputStream.read(buf);
			}
			retCode = "0";
			retMsg = "文件下载成功";
			data="文件保存路径为:"+savePath+fileName;
		} catch (Exception e) {
			log.info("----文件下载异常:{}--信息:{}-->", e.getMessage(), e.getStackTrace());
			retCode = "999";
			retMsg = "文件下载异常,"+e.getMessage();
		} finally {
			try {
				bufferedOutputStream.close();
				bufferedInputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		ws.setRetcode(retCode);
		ws.setErrorMsg(retMsg);
		ws.setData(data);
		return ws;
	}



	/**
	 * http方式下载到临时文件里
	 * @param fileUrlPath 下载临时文件的路径
	 * @param file 下载到文件
	 * @param headers 下载临时文件需要的http头信息
	 * @param retries 重试次数
	 * @return 文件
	 */
	public static File  downloadNetWorkFileAsMedia(String fileUrlPath, File file, Map<String,String> headers, int retries){
		if(!StringUtils.hasText(fileUrlPath))
		{
			log.warn("下载路径为空，fileUrlPath: {} 生产文件:{}",fileUrlPath,file.getAbsolutePath());
			return null;
		}
		int count=0;
		while(count<retries){
			try {
				downloadNetWorkFileAsMedia(fileUrlPath, file, headers);
				if (file.length() < 10) {
					file.delete();
					log.warn("第{}次文件下载太小，正在重试，fileUrlPath: {} 文件路径:{}。 大小：{}",count,fileUrlPath,file.getAbsolutePath(),file.length());
					downloadNetWorkFileAsMedia(fileUrlPath, file, headers);
				}
			}catch (Exception e){
				log.warn("第{}次下载失败，正在重试，fileUrlPath: {} 生产文件:{}",count+1,fileUrlPath,file.getAbsolutePath());
				try {
					Thread.sleep(300);
				}catch (Exception ex){
					log.warn("休眠：第{}次下载失败，正在重试，fileUrlPath: {} 生产文件:{}",count,fileUrlPath,file.getAbsolutePath());
				}
			}
			count++;
		}
		return file;
	}




	/**
	 * http方式下载到临时文件里
	 * @param fileUrlPath 下载临时文件的路径
	 * @param file 下载到文件
	 * @param headers 下载临时文件需要的http头信息
	 * @return 文件
	 */
	public static File  downloadNetWorkFileAsMedia( String fileUrlPath,File file, Map<String,String> headers){
		InputStream inputStream = null;
		try {
			if(!file.exists()) {
				file.createNewFile();
			}
			inputStream = getNetWorkFileToInputStream(fileUrlPath, headers);
			if (null != inputStream){
				//outputStream write inputStream 可能导致音视频文件长度有问题 所以需要中转一下 FileInputStream
				FileOutputStream fileOutputStream = new FileOutputStream(file);
				FileCopyUtils.copy(inputStream, fileOutputStream);
			}
			return file;
		}catch (Exception exception){
			log.error("downloadNetWorkAudioFileAsMedia 下载网络文件失败，地址是{}, 异常信息{}!", fileUrlPath, exception);
			if(file.exists()){
				file.delete();
			}
			return null;
		}finally {
			if (null != inputStream){
				try {
					inputStream.close();
				}catch (Exception e){
					e.printStackTrace();
				}
			}
		}
	}



	/**
	 * 下载网络文件获取输入流
	 * @param fileUrlPath 网络文件地址
	 * @param headers 设置网络头信息
	 * @return InputStream
	 * @throws IOException io异常
	 */
	public static InputStream getNetWorkFileToInputStream(String fileUrlPath, Map<String,String> headers) throws IOException {
		URL urlConnection = new URL(fileUrlPath);
		HttpURLConnection connection = (HttpURLConnection) urlConnection.openConnection();
		connection.setRequestMethod("GET");
		connection.setConnectTimeout(600000);//连接超时 单位毫秒
		connection.setReadTimeout(600000);//读取超时 单位毫秒

		if (headers.containsKey(REQ_HEADER_GUID_KEY)){
			connection.setRequestProperty("guid", headers.get("guid"));
		}else if (headers.containsKey(REQ_HEADER_AUTHORIZATION_KEY)){
			String username = headers.get("Authorization").split(",")[0];
			String password = headers.get("Authorization").split(",")[1];
			log.info("curt is basic auth is {}","Basic " + HttpHeaders.encodeBasicAuth(username, password, null));
			connection.setRequestProperty("Authorization", "Basic " + HttpHeaders.encodeBasicAuth(username, password, null));
		}else {
			headers.entrySet().forEach((entry)->{
						connection.setRequestProperty(entry.getKey(), entry.getValue());
					}
			);
		}

		connection.setConnectTimeout(1000 * 5);
		connection.connect(); //连接网络资源
		int responseCode = connection.getResponseCode();
		if(responseCode == HttpURLConnection.HTTP_OK) {
			log.debug("url download rv header info is:{}", JsonPathUtil.getJson(connection.getHeaderFields()));
			log.debug("url download rv info is:{}", JsonPathUtil.getJson(connection.getResponseMessage()));
			return connection.getInputStream();
		}else {
			log.warn("下载失败 错误码: {} 错误信息: {},url download rv header info is:{}",connection.getResponseCode(),connection.getResponseMessage(), JsonPathUtil.getJson(connection.getHeaderFields()));
			log.warn("下载失败,url download rv info is:{}", JsonPathUtil.getJson(connection.getResponseMessage()));
		}
		return null;
	}







	/**
	 * 将声音或录像返回前段
	 * @param response HttpServletResponse
	 * @param file 读取的文件类容
	 */
	public static void responseFile(HttpServletResponse response,File file){
		FileInputStream fis = null;
		try {
			if (file.exists()){
				ServletOutputStream out = response.getOutputStream();
				fis = new FileInputStream(file);
				int len;
				byte[] b = new byte[1024];
				while ((len = fis.read(b)) != -1) {
					out.write(b, 0, len);
				}
			}
		}catch (Exception exception){
			log.error("临时文件路径，地址是{}, 异常信息{}!", file.getAbsoluteFile(), exception.getMessage());
		}finally {
			if (fis != null){
				try {
					fis.close();
				}catch (Exception e){
					e.printStackTrace();
				}
			}
		}

	}

















	/**
	 * 下载网络流媒体文件
	 * @param response 下载输出流
	 * @param fileUrlPath 需要下载文件的路径
	 * @date 2021/2/24 17:09
	 */
	public static void downloadNetWorkFileAsMedia(HttpServletResponse response,
												  String fileUrlPath, String fileName,
												  Map<String,String> headers){
		InputStream inputStream = null;
		FileInputStream fis = null;
		try {

			inputStream = getNetWorkFileToInputStream(fileUrlPath, headers);

			if (null != inputStream){
				//outputStream write inputStream 可能导致音视频文件长度有问题 所以需要中转一下 FileInputStream
				String tmpDir = System.getProperty("java.io.tmpdir");

				File file = new File(UUID.randomUUID()+fileName);
				FileOutputStream fileOutputStream = new FileOutputStream(file);
				FileCopyUtils.copy(inputStream, fileOutputStream);

				ServletOutputStream out = response.getOutputStream();
				fis = new FileInputStream(file);
				int len;
				byte[] b = new byte[1024];
				while ((len = fis.read(b)) != -1) {
					out.write(b, 0, len);
				}
			}

		}catch (Exception exception){
			log.error("下载网络文件失败，地址是{}, 异常信息{}!", fileUrlPath, exception.getMessage());
		}finally {
			if (null != inputStream){
				try {
					inputStream.close();
				}catch (Exception e){
					e.printStackTrace();
				}
			}
			if (fis != null){
				try {
					fis.close();
				}catch (Exception e){
					e.printStackTrace();
				}
			}
		}
	}









}
